"""
文件相关的请求/响应数据模型
"""
from datetime import datetime
from typing import Optional, List

from pydantic import BaseModel, Field, validator, ConfigDict


class FileUploadRequest(BaseModel):
    """
    文件上传请求模型
    """
    biz_type: Optional[str] = Field(None, description="业务类型，如DEVICE、WORK_ORDER等", max_length=32)
    biz_id: Optional[str] = Field(None, description="业务ID", max_length=64)

    @validator('biz_type')
    def validate_biz_type(cls, v):
        """验证业务类型格式"""
        if v and not v.strip():
            raise ValueError("业务类型不能为空字符串")
        if v:
            # 限制业务类型格式为大写字母和下划线
            if not v.replace('_', '').replace('-', '').isalnum():
                raise ValueError("业务类型只能包含字母、数字、下划线和连字符")
        return v.strip() if v else v

    @validator('biz_id')
    def validate_biz_id(cls, v):
        """验证业务ID格式"""
        if v and not v.strip():
            raise ValueError("业务ID不能为空字符串")
        return v.strip() if v else v


class FileUploadResponse(BaseModel):
    """
    文件上传响应模型
    """
    id: int = Field(..., description="文件ID")
    url: str = Field(..., description="访问URL")
    name: str = Field(..., description="文件名")
    size: Optional[int] = Field(None, description="文件大小（字节）")
    ext: Optional[str] = Field(None, description="文件扩展名")
    md5: Optional[str] = Field(None, description="文件MD5值")
    mime_type: Optional[str] = Field(None, description="MIME类型")

    @property
    def size_mb(self) -> Optional[float]:
        """返回以MB为单位的文件大小"""
        if self.size is None:
            return None
        return round(self.size / (1024 * 1024), 2)


class FileInfoResponse(BaseModel):
    """
    文件信息响应模型
    """
    id: int = Field(..., description="文件ID")
    biz_type: Optional[str] = Field(None, description="业务类型")
    biz_id: Optional[str] = Field(None, description="业务ID")
    file_name: str = Field(..., description="文件名")
    file_ext: Optional[str] = Field(None, description="文件扩展名")
    file_size: Optional[int] = Field(None, description="文件大小（字节）")
    mime_type: Optional[str] = Field(None, description="MIME类型")
    url: Optional[str] = Field(None, description="访问URL")
    md5: Optional[str] = Field(None, description="文件MD5值")
    status: int = Field(..., description="状态：1有效，0无效")
    creator_id: Optional[int] = Field(None, description="上传用户ID")
    create_time: datetime = Field(..., description="创建时间")
    update_time: datetime = Field(..., description="更新时间")

    @property
    def size_mb(self) -> Optional[float]:
        """返回以MB为单位的文件大小"""
        if self.file_size is None:
            return None
        return round(self.file_size / (1024 * 1024), 2)

    @property
    def is_image(self) -> bool:
        """判断是否为图片文件"""
        if not self.mime_type:
            return False
        return self.mime_type.startswith('image/')

    @property
    def is_document(self) -> bool:
        """判断是否为文档文件"""
        if not self.mime_type:
            return False
        doc_types = [
            'application/pdf',
            'application/msword',
            'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
            'application/vnd.ms-excel',
            'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
            'text/plain',
            'text/csv'
        ]
        return self.mime_type in doc_types

    model_config = ConfigDict(from_attributes=True)


class FileListRequest(BaseModel):
    """
    文件列表查询请求模型
    """
    page: int = Field(1, description="页码", ge=1)
    page_size: int = Field(20, description="每页大小", ge=1, le=100)
    biz_type: Optional[str] = Field(None, description="业务类型筛选")
    biz_id: Optional[str] = Field(None, description="业务ID筛选")
    creator_id: Optional[int] = Field(None, description="上传用户ID筛选")
    file_ext: Optional[str] = Field(None, description="文件扩展名筛选")
    mime_type: Optional[str] = Field(None, description="MIME类型筛选")
    status: Optional[int] = Field(None, description="文件状态筛选", ge=0, le=1)
    keyword: Optional[str] = Field(None, description="文件名关键词搜索", max_length=50)

    @validator('keyword')
    def validate_keyword(cls, v):
        """验证关键词格式"""
        if v and not v.strip():
            raise ValueError("关键词不能为空字符串")
        return v.strip() if v else v


class FileListResponse(BaseModel):
    """
    文件列表响应模型
    """
    total: int = Field(..., description="总数量")
    items: List[FileInfoResponse] = Field(default_factory=list, description="文件列表")
    page: int = Field(..., description="当前页码")
    page_size: int = Field(..., description="每页大小")
    total_pages: int = Field(..., description="总页数")

    @property
    def has_next(self) -> bool:
        """是否有下一页"""
        return self.page < self.total_pages

    @property
    def has_prev(self) -> bool:
        """是否有上一页"""
        return self.page > 1


class FileUpdateRequest(BaseModel):
    """
    文件信息更新请求模型
    """
    biz_type: Optional[str] = Field(None, description="业务类型", max_length=32)
    biz_id: Optional[str] = Field(None, description="业务ID", max_length=64)
    status: Optional[int] = Field(None, description="文件状态：1有效，0无效", ge=0, le=1)

    @validator('biz_type')
    def validate_biz_type(cls, v):
        """验证业务类型格式"""
        if v and not v.strip():
            raise ValueError("业务类型不能为空字符串")
        if v:
            if not v.replace('_', '').replace('-', '').isalnum():
                raise ValueError("业务类型只能包含字母、数字、下划线和连字符")
        return v.strip() if v else v

    @validator('biz_id')
    def validate_biz_id(cls, v):
        """验证业务ID格式"""
        if v and not v.strip():
            raise ValueError("业务ID不能为空字符串")
        return v.strip() if v else v


class FileStatisticsResponse(BaseModel):
    """
    文件统计响应模型
    """
    total_count: int = Field(..., description="文件总数")
    total_size: int = Field(..., description="文件总大小（字节）")
    image_count: int = Field(0, description="图片文件数")
    document_count: int = Field(0, description="文档文件数")
    other_count: int = Field(0, description="其他文件数")

    @property
    def total_size_mb(self) -> float:
        """返回以MB为单位的总大小"""
        return round(self.total_size / (1024 * 1024), 2)

    @property
    def total_size_gb(self) -> float:
        """返回以GB为单位的总大小"""
        return round(self.total_size / (1024 * 1024 * 1024), 2)

    @property
    def average_size_mb(self) -> float:
        """返回平均文件大小（MB）"""
        if self.total_count == 0:
            return 0
        return round((self.total_size / self.total_count) / (1024 * 1024), 2)


class FileBatchUploadRequest(BaseModel):
    """
    批量文件上传请求模型
    """
    biz_type: Optional[str] = Field(None, description="业务类型", max_length=32)
    biz_id: Optional[str] = Field(None, description="业务ID", max_length=64)
    max_files: int = Field(10, description="最大文件数量", ge=1, le=50)

    @validator('biz_type')
    def validate_biz_type(cls, v):
        """验证业务类型格式"""
        if v and not v.strip():
            raise ValueError("业务类型不能为空字符串")
        if v:
            if not v.replace('_', '').replace('-', '').isalnum():
                raise ValueError("业务类型只能包含字母、数字、下划线和连字符")
        return v.strip() if v else v


class FileBatchUploadResponse(BaseModel):
    """
    批量文件上传响应模型
    """
    success_count: int = Field(..., description="成功上传数量")
    failed_count: int = Field(..., description="失败上传数量")
    success_files: List[FileUploadResponse] = Field(default_factory=list, description="成功上传的文件")
    failed_files: List[dict] = Field(default_factory=list, description="失败上传的文件信息")

    @property
    def total_count(self) -> int:
        """总文件数量"""
        return self.success_count + self.failed_count

    @property
    def success_rate(self) -> float:
        """成功率"""
        if self.total_count == 0:
            return 0
        return round((self.success_count / self.total_count) * 100, 2)


class FileDownloadRequest(BaseModel):
    """
    文件下载请求模型
    """
    file_id: int = Field(..., description="文件ID", gt=0)
    download_type: str = Field("direct", description="下载类型：direct-直接下载，preview-预览")

    @validator('download_type')
    def validate_download_type(cls, v):
        """验证下载类型"""
        if v not in ["direct", "preview"]:
            raise ValueError("下载类型只能是 direct 或 preview")
        return v


class FileDeleteRequest(BaseModel):
    """
    文件删除请求模型
    """
    file_ids: List[int] = Field(..., description="要删除的文件ID列表", min_items=1, max_items=50)
    force_delete: bool = Field(False, description="是否强制删除（删除物理文件）")

    @validator('file_ids')
    def validate_file_ids(cls, v):
        """验证文件ID列表"""
        if not v:
            raise ValueError("文件ID列表不能为空")
        if len(v) != len(set(v)):
            raise ValueError("文件ID列表中存在重复项")
        for file_id in v:
            if file_id <= 0:
                raise ValueError("文件ID必须大于0")
        return v


class FileDeleteResponse(BaseModel):
    """
    文件删除响应模型
    """
    success_count: int = Field(..., description="成功删除数量")
    failed_count: int = Field(..., description="失败删除数量")
    failed_ids: List[int] = Field(default_factory=list, description="删除失败的文件ID")

    @property
    def total_count(self) -> int:
        """总删除数量"""
        return self.success_count + self.failed_count
